home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 January / macformat-033.iso / mac / Shareware City / Control Strip / ES 1.0 Package / Programming Stuff / ESDemo.c ƒ / ESDemo.c next >
Encoding:
C/C++ Source or Header  |  1995-10-30  |  23.0 KB  |  723 lines  |  [TEXT/MMCC]

  1. /* ---------------------------------------------------------------------------
  2. ESDemo.c
  3.     
  4.     ©1995 Ammon Skidmore, Skidperfect Software Inc.  All Rights Reserved.
  5.     
  6.     Freeware: use and steal whatever code you want for your own modules.
  7.     
  8.     A not-so-simple Control Strip Module "shell" that demonstrates many of
  9.     the powerful new features that Extensions Strip can give to modules while
  10.     retaining backward compatibility with Control/Desktop Strip.
  11.     
  12.     Key features of this module:
  13.     -    Fat binary.
  14.     -    Intelligent drag handling.  Under Control/Desktop Strip the draggable
  15.         area is the location of the module's icon.  Under Extensions Strip this
  16.         area is the total amount of space that the module takes up.
  17.     -    2 out of the 3 possible methods for sending "safe" AppleEvents that don't rely
  18.         upon the front process' context.  Under Control/Desktop Strip the event is still
  19.         sent, but will not work if the front process does not support Apple Events.
  20.     -    Ability to get key presses under Extensions Strip without having to install
  21.         a custom jGNE filter (as my Terminator Strip module does.)
  22.     -    Ability to change the sdevFeatures without having to restart.  Examples are
  23.         given for changing almost all of the possible features, even locking and
  24.         unlocking my sdev code.
  25.     
  26.     How to build the FAT module:
  27.     -    Compile the 68K project first.  It will create a clean module (code + what's
  28.         in the resource file "ESDemo.µ.rsrc") because the "Merge To File" option is OFF.
  29.     -    Compile the PPC project last.  It will append its code to the module because
  30.         the "Merge To File" option is ON.  Note that you will have to change the
  31.         access paths to allow the project to find the "ExtensionsStripLib" shared library.
  32.     
  33.     Other notes:
  34.     -    For PPC compiling, remember to use 'weak links' to shared libraries that may not
  35.         be on every user's computer.  Not doing so will cause a crash because Extensions
  36.         Strip will be forced to quit if the library is not present.  Modules should use
  37.         Gestalt calls to determine the presence of libraries they use.
  38.         For example, this project has a weak link to the DragLib, yet it does not have
  39.         one to the ExtensionsStripLib or the InterfaceLib because these two libraries
  40.         will always be present (PPC ES will not load without the ExtensionsStripLib.)
  41.     
  42. Version History
  43. -=-=-=-=-=-=-=-
  44. 1.0        8/95 - 10/95    by Ammon Skidmore
  45.         10/30/95        made THINK compiler friendly by Vincent Tan
  46.  
  47. -=-=-=-=-=-=-=-
  48. Framework taken from the CSShell.c Control Strip Sample by Martin R. Wachter.
  49. It is freely availible and can be found on the usual UMich/Info-Mac mirrors.
  50. --------------------------------------------------------------------------- */
  51.  
  52. #ifdef powerc
  53.     // for Metrowerks' linker, this defines the mixed-mode interface for main().
  54.     ProcInfoType __procinfo = kPascalStackBased
  55.          | RESULT_SIZE(SIZE_CODE(sizeof(long)))
  56.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  57.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(long)))
  58.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(Rect*)))
  59.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(WindowRef)));
  60. #endif
  61.  
  62. #include "ESDemo.h"
  63.  
  64. #ifndef __GESTALT__
  65.     #include <Gestalt.h>
  66. #endif  __GESTALT__
  67.  
  68. #ifndef    FALSE
  69.     #define    FALSE    false
  70. #endif
  71.  
  72. #ifndef    TRUE
  73.     #define    TRUE    true
  74. #endif
  75.  
  76. /******************************************************************************
  77.  main: Control Strip's entry point into our sdev code
  78.  ******************************************************************************/
  79. pascal long main (long message, long params, Rect *statusRect, WindowRef statusPort)
  80. {
  81.     long        result = 0L;
  82.     
  83.     switch (message)
  84.     {
  85.         //
  86.         // Default Control Strip selectors:
  87.         //
  88.         
  89.         case sdevInitModule:         // check environs, allocate globals
  90.             result = sdevInit(statusPort);
  91.         break;
  92.         
  93.         case sdevCloseModule:         // release my memory
  94.             sdevClose((MyGlobalHandle) params, statusPort);
  95.         break;
  96.         
  97.         case sdevFeatures:             // let the strip track the mouse down
  98.             result = (**(MyGlobalHandle) params).currentFeatures;
  99.             break;
  100.         break;
  101.         
  102.         case sdevGetDisplayWidth:    // inform the strip how much strip space we need
  103.             result = kIconWidth + width((*(**(MyGlobalHandle) params).myArrowPict)->picFrame);
  104.         break;
  105.         
  106.         case sdevPeriodicTickle:    // never called by Extensions Strip because we
  107.         {
  108.                                     // returned the sdevDontPeriodicTickle bit.
  109.             Rect    viewRect = *statusRect;
  110.             
  111.             // update the draggable box upon each idle cycle in case the user
  112.             // shrunk the Control Strip bar so that we are not visible, but our
  113.             // old position still is because the end of the bar is there.
  114.             viewRect.right = viewRect.left + kIconWidth;
  115.             (**(MyGlobalHandle) params).myBox = viewRect;
  116.             break;
  117.         }
  118.         
  119.         case sdevDrawStatus:         // draw my icon and arrow pict
  120.             sdevDraw((MyGlobalHandle) params, statusRect, statusPort);
  121.         break;
  122.         
  123.         case sdevMouseClick:         // the mouse was clicked & released in my button
  124.             result = sdevClick((MyGlobalHandle) params, statusRect, statusPort);
  125.         break;
  126.         
  127.         case sdevSaveSettings:        // no settings in this module
  128.         break;
  129.         
  130.         case sdevShowBalloonHelp:    // we have a custom ballon help string
  131.         {
  132.             Str255    helpString;
  133.             
  134.             SBGetDetachedIndString(helpString, (**(MyGlobalHandle) params).myStrings, kHelpStringIndex);
  135.             SBShowHelpString(statusRect, helpString);
  136.             break;
  137.         }
  138.         
  139.         //
  140.         // ES specific selectors:
  141.         // Note that we check for the presence of ES just in case...
  142.         //
  143.         
  144.         case sdevInAppContext:        // we are inside Extensions Strip's context so
  145.                                     // is is safe to send Apple Events from here.
  146.         {
  147.             ProcessSerialNumber    finderPSN;
  148.             ProcessInfoRec        infoRec;
  149. #define        kFinderType            'FNDR'
  150. #define        kSysCreator            'MACS'
  151.  
  152.             if ((**(MyGlobalHandle) params).hasExtensionsStrip) {
  153.                 infoRec.processInfoLength    =    sizeof(ProcessInfoRec);
  154.                 infoRec.processName            =    nil;    //    no name wanted processName;
  155.                 infoRec.processAppSpec        =    nil;    //    no spec wanted &procSpec;
  156.                 
  157.                 if (FindAProcess(kFinderType, kSysCreator, &finderPSN, &infoRec) == noErr)
  158.                     QuitProcess(finderPSN, FALSE);    // FALSE because we don't HAVE to use
  159.                                                     // _SBSimpleAESend here
  160.             }
  161.             break;
  162.         }
  163.         
  164.         case sdevInterceptedEvent:    // a chance to look at and modify the current event
  165.         {
  166.             EventRecord    *theEvent;
  167.             
  168.             if ((**(MyGlobalHandle) params).hasExtensionsStrip) {
  169.                 // for demonstration's purpose, we'll intercept command + *
  170.                 // (* on the keypad only since cmd-shift-8 is an FKEY combo that
  171.                 // is intercepted by the System.)
  172.                 theEvent = SBGetCurrentEvent();
  173.             // we can assume a keydown since our mask filters out the rest.
  174.             //    if (theEvent->what == keyDown)
  175.                     if (theEvent->modifiers & cmdKey) {
  176.                         switch (theEvent->message & charCodeMask)
  177.                         {
  178.                             case '*':
  179.                                 SysBeep(3);
  180.                                 theEvent->what = nullEvent;        // don't pass on the event
  181.                                 break;
  182.                             default:
  183.                                 break;
  184.                         }
  185.                     }
  186.             }
  187.             break;
  188.         }
  189.         
  190.         case sdevDragAccept:    // let Extensions Strip know if we won't handle the drag
  191.             if ((**(MyGlobalHandle) params).hasExtensionsStrip &&
  192.                         !(**(MyGlobalHandle) params).canAcceptDrag)
  193.                 result = 1;                // we don't accept the drag
  194.         break;
  195.         
  196.         case sdevEventMask:        // let Extensions Strip know we want key down events
  197.             if ((**(MyGlobalHandle) params).hasExtensionsStrip)
  198.                 result = keyDownMask;    // our GNE style event mask
  199.         break;
  200.     }
  201.     
  202.     return (result);
  203. }
  204.  
  205. /******************************************************************************
  206.  sdevClick: handle a click in our status rect
  207.  ******************************************************************************/
  208. long sdevClick(MyGlobalHandle globH, const Rect    *statusRect, WindowRef statusPort)
  209. {
  210.     short            menuID;
  211.     MenuHandle        menuH = (**globH).myMenuH;    // local copy to save deferencing
  212.     long            result = 0L;
  213.     char            itemMark;
  214.     short            theBit;
  215.     
  216.     // reflect the current features in th popup menu
  217.     itemMark = ((**globH).currentFeatures & (1L<<sdevWantMouseClicks)) ? sdevMenuItemMark : noMark;
  218.     SetItemMark(menuH, kHiliteClicks, itemMark);
  219.     itemMark = ((**globH).currentFeatures & (1L<<sdevHasCustomHelp)) ? sdevMenuItemMark : noMark;
  220.     SetItemMark(menuH, kCustomBalloons, itemMark);
  221.     itemMark = ((**globH).currentFeatures & (1L<<sdevInterceptAllEvents)) ? sdevMenuItemMark : noMark;
  222.     SetItemMark(menuH, kCheckKeyDowns, itemMark);
  223.     itemMark = ((**globH).currentFeatures & (1L<<sdevHasDragHandlers)) ? sdevMenuItemMark : noMark;
  224.     SetItemMark(menuH, kUseDragNDrop, itemMark);
  225.     
  226.     // disable what COntrol/Desktop Strip doesn't support
  227.     if (!(**globH).hasExtensionsStrip) {
  228.         DisableItem(menuH, kSafeFinderQuit2);
  229.         SetItemMark(menuH, kCheckKeyDowns, noMark);
  230.     }
  231.     
  232.     // show our popup menu
  233.     menuID = SBTrackPopupMenu(statusRect, menuH);
  234.     
  235.     switch (menuID){
  236.         
  237.         case kBeepIfPPC:
  238. #ifdef powerc
  239.             SysBeep(3);
  240. #endif
  241.             break;
  242.         
  243.         case kHiliteClicks:
  244.             theBit = sdevWantMouseClicks;
  245.             // pass on
  246.         
  247.         case kCustomBalloons:
  248.             if (menuID == kCustomBalloons)
  249.                 theBit = sdevHasCustomHelp;
  250.             // pass on
  251.         
  252.         case kCheckKeyDowns:
  253.             if (menuID == kCheckKeyDowns)
  254.                 theBit = sdevInterceptAllEvents;
  255.             // pass on
  256.         
  257.         case kUseDragNDrop:
  258.             if ((**globH).hasExtensionsStrip) {
  259.                 if (menuID == kUseDragNDrop) {
  260.                     theBit = sdevHasDragHandlers;
  261.                     // Install/remove handlers for fun.  We can also now
  262.                     // unlock our code, all for demonstration purposes.
  263.                     if ((**globH).currentFeatures & (1L<<sdevHasDragHandlers)) {
  264.                         (**globH).currentFeatures -= (1L<<sdevKeepModuleLocked);
  265.                         RemoveDragHandlers(statusPort, globH);
  266.                         DisableItem(menuH, kDragFiles);
  267.                         DisableItem(menuH, kDragTextClippings);
  268.                     } else {
  269.                         (**globH).currentFeatures += (1L<<sdevKeepModuleLocked);
  270.                         InstallDragHandlers(statusPort, globH);
  271.                         EnableItem(menuH, kDragFiles);
  272.                         EnableItem(menuH, kDragTextClippings);
  273.                     }
  274.                 }
  275.                 
  276.                 // handle the passed bit
  277.                     if ((**globH).currentFeatures & (1L<<theBit))
  278.                         (**globH).currentFeatures -= (1L<<theBit);
  279.                     else
  280.                         (**globH).currentFeatures += (1L<<theBit);
  281.                     result = (1L<<sdevFeaturesChange);    // request a sdevFeatures call
  282.             }
  283.             break;
  284.         
  285.         case kDragFiles:
  286.             (**globH).acceptFiles = !(**globH).acceptFiles;
  287.             itemMark = (**globH).acceptFiles ? sdevMenuItemMark : noMark;
  288.             SetItemMark(menuH, kDragFiles, itemMark);
  289.             break;
  290.         
  291.         case kDragTextClippings:
  292.             (**globH).acceptText = !(**globH).acceptText;
  293.             itemMark = (**globH).acceptText ? sdevMenuItemMark : noMark;
  294.             SetItemMark(menuH, kDragTextClippings, itemMark);
  295.             break;
  296.         
  297.         case kSafeFinderQuit1: {
  298.             ProcessSerialNumber    finderPSN;
  299.             ProcessInfoRec        infoRec;
  300.  
  301.             infoRec.processInfoLength    =    sizeof(ProcessInfoRec);
  302.             infoRec.processName            =    nil;    //    no name wanted processName;
  303.             infoRec.processAppSpec        =    nil;    //    no spec wanted &procSpec;
  304.             
  305.             if (FindAProcess(kFinderType, kSysCreator, &finderPSN, &infoRec) == noErr)
  306.                 QuitProcess(finderPSN, (**globH).hasExtensionsStrip);
  307.             break;
  308.             }
  309.         
  310.         case kSafeFinderQuit2:
  311.             // request sdevInAppContext to be called once within Extensions Strip's context
  312.             result = (1L<<sdevQueueModule);
  313.             break;
  314.                         
  315.         case kCloseDown:
  316.             result = (1L<<sdevCloseNow);
  317.             break;
  318.     }                //end switch
  319.     
  320.     return(result);
  321. }
  322.  
  323. /******************************************************************************
  324.  sdevInit: allocate memory for our globals and init our globals
  325.  ******************************************************************************/
  326. long sdevInit(WindowRef statusPort)
  327. {
  328.     MyGlobalHandle    globH;
  329.     
  330.     //
  331.     // get some memory
  332.     //
  333.     globH = (MyGlobalHandle) NewHandleClear(sizeof(MyGlobals));
  334.     if (!globH)
  335.         goto exit;
  336.     HLock((Handle)globH);
  337.  
  338.     //
  339.     // get our icon suite
  340.     //
  341.         if (SBGetDetachIconSuite(&(**globH).iconSuite, rIconSuiteId, svAllSmallData) != noErr) goto exit;
  342.     //
  343.     // get our string list
  344.     //
  345.         (**globH).myStrings = GetResource('STR#', rMyStringsID);
  346.         if (!(**globH).myStrings) goto exit;
  347.         DetachResource((**globH).myStrings);
  348.     //
  349.     // get our popup menu
  350.     //
  351.         (**globH).myMenuH = GetMenu(rPopupMenuID);
  352.         if (!(**globH).myMenuH) goto exit;
  353.         DetachResource((Handle)(**globH).myMenuH);
  354.     //
  355.     // get our arrow picture
  356.     //
  357.         (**globH).myArrowPict = GetPicture(rArrowPictID);
  358.         if (!(**globH).myArrowPict) goto exit;
  359.         DetachResource((Handle)(**globH).myArrowPict);
  360.     //
  361.     // setup our initial features
  362.     //
  363.         (**globH).currentFeatures = (
  364.                       (1L<<sdevWantMouseClicks)        // we handle mouse down
  365.                     | (1L<<sdevDontAutoTrack)        // we track the mouse, too
  366.                     | (1L<<sdevHasCustomHelp)        // custom help string
  367.                     | (1L<<sdevKeepModuleLocked)        // I need to be locked
  368.                                                     //         for drag-n-drop.
  369.                 );
  370.     //
  371.     // determine if Extensions Strip is running.
  372.     // If so, get my reference number and setup ES specific feature flags
  373.     //
  374.         (**globH).hasExtensionsStrip = HasExtensionsStrip();
  375.         if ((**globH).hasExtensionsStrip)
  376.         {
  377.             (**globH).myReferenceNum = SBGetMyReferenceNum();
  378.             (**globH).currentFeatures +=
  379.                 (
  380.                       (1L<<sdevHasDragHandlers)        // flag that we have drag handlers
  381.                     | (1L<<sdevDontPeriodicTickle)    // we don't need any idle time
  382.                     | (1L<<sdevInterceptAllEvents)    // get all events under Extensions Strip
  383.                 );
  384.         }
  385.     //
  386.     // setup the drag stuff
  387.     //
  388.         InstallDragHandlers(statusPort, globH);
  389.         (**globH).acceptFiles = true;
  390.         SetItemMark((**globH).myMenuH, kDragFiles, sdevMenuItemMark);
  391.     //
  392.     // set my handle free and return its value
  393.     //
  394.         HUnlock((Handle)globH);
  395.         return ((long) globH);
  396.     
  397.     //
  398.     // did not get any memory, don't install
  399.     //
  400. exit:
  401.     return (-1L);
  402. }
  403.  
  404. /******************************************************************************
  405.  sdevClose: free memory for our globals
  406.  ******************************************************************************/
  407. void sdevClose(MyGlobalHandle globH, WindowRef statusPort)
  408. {
  409. // useful macros:
  410. #define    myDisposeHandle(h)\
  411.     if ((h) != nil)\
  412.         DisposeHandle((Handle) (h))
  413. #define    myDisposeIconSuite(h, p1)\
  414.     if ((h) != nil)\
  415.         DisposeIconSuite(h, p1)
  416.  
  417. // dispose of everything:
  418.     if (globH){
  419.         myDisposeIconSuite((**globH).iconSuite, true);
  420.         myDisposeHandle((**globH).myMenuH);
  421.         myDisposeHandle((**globH).myStrings);
  422.         myDisposeHandle((**globH).myArrowPict);
  423.         
  424.         RemoveDragHandlers(statusPort, globH);
  425.         
  426.         DisposeHandle((Handle) globH);
  427.     }
  428. }
  429.  
  430. /******************************************************************************
  431.  sdevDraw: draw our icon and arrow pict
  432.  ******************************************************************************/
  433. void sdevDraw(MyGlobalHandle globH, Rect *statusRect, WindowRef statusPort)
  434. {
  435.     Rect        viewRect = *statusRect;
  436.     short        arrowHeight = 0;
  437.     PicHandle    myArrowPict = (**globH).myArrowPict;    // local copy to save deferencing
  438.     
  439.     //
  440.     // update the drag area (only required for Control/Desktop Strip)
  441.     //
  442.     viewRect.right = viewRect.left + kIconWidth;
  443.     (**globH).myBox = viewRect;
  444.     
  445.     //
  446.     // Draw our icon
  447.     //
  448.     DrawMyIcon(globH, false);
  449.     
  450.     //
  451.     // Draw our right-arrow pict to show that we have a popup menu
  452.     //
  453.     if (myArrowPict){
  454.         arrowHeight = height((*myArrowPict)->picFrame);
  455.         viewRect.left = viewRect.right;
  456.         viewRect.right += width((*myArrowPict)->picFrame);
  457.         viewRect.top += ((height(viewRect) - arrowHeight) >> 1);
  458.         viewRect.bottom = viewRect.top + arrowHeight;
  459.         DrawPicture(myArrowPict, &viewRect);
  460.     }
  461. }
  462.  
  463. #pragma mark -
  464.  
  465. /******************************************************************************
  466.  HasDragMgr: determine if the Drag Manager exists, and supports floaters
  467.  ******************************************************************************/
  468. Boolean    HasDragMgr(void)
  469. {
  470.     long    gestaltResponse;
  471.  
  472.     return(    (Gestalt(gestaltDragMgrAttr, &gestaltResponse) == noErr) &&
  473.             (gestaltResponse & (1L << gestaltDragMgrPresent)) &&
  474.             (gestaltResponse & (1L << gestaltDragMgrFloatingWind)) );
  475. }
  476.  
  477. /******************************************************************************
  478.  InstallDragHandlers: install & create everything having to do with drag handlers
  479.  ******************************************************************************/
  480. void InstallDragHandlers(WindowRef statusPort, MyGlobalHandle globH)
  481. {
  482.     // local copies
  483.     DragTrackingHandlerUPP    myTrackingUPP;
  484.     DragReceiveHandlerUPP    myReceiveUPP;
  485.     
  486.     if (HasDragMgr()) {
  487.         myTrackingUPP = NewDragTrackingHandlerProc(MyTrackingHandler);
  488.         myReceiveUPP = NewDragReceiveHandlerProc(MyReceiveDropHandler);
  489.         
  490.         if (myTrackingUPP && myReceiveUPP) {    // got UPPs successfully
  491.             InstallTrackingHandler(myTrackingUPP, statusPort, (void*) globH);
  492.             InstallReceiveHandler(myReceiveUPP, statusPort, (void*) globH);
  493.         }
  494.         
  495.         (**globH).myTrackingUPP = myTrackingUPP;
  496.         (**globH).myReceiveUPP = myReceiveUPP;
  497.     } else {
  498.         // disable the drag-related menu items
  499.         // (doesn't move memory)
  500.         DisableItem((**globH).myMenuH, kUseDragNDrop);
  501.         DisableItem((**globH).myMenuH, kDragFiles);
  502.         DisableItem((**globH).myMenuH, kDragTextClippings);
  503.     }
  504. }
  505.  
  506. /******************************************************************************
  507.  RemoveDragHandlers: remove & dispose everything having to do with drag handlers
  508.  ******************************************************************************/
  509. void RemoveDragHandlers(WindowRef statusPort, MyGlobalHandle globH)
  510. {
  511.     // local copies
  512.     DragTrackingHandlerUPP    myTrackingUPP = (**globH).myTrackingUPP;
  513.     DragReceiveHandlerUPP    myReceiveUPP = (**globH).myReceiveUPP;
  514.     
  515.     if (myTrackingUPP) {
  516.         RemoveTrackingHandler(myTrackingUPP, statusPort);
  517.         DisposeRoutineDescriptor(myTrackingUPP);
  518.         (**globH).myTrackingUPP = 0L;
  519.     }
  520.     
  521.     if (myReceiveUPP) {
  522.         RemoveReceiveHandler(myReceiveUPP, statusPort);
  523.         DisposeRoutineDescriptor(myReceiveUPP);
  524.         (**globH).myReceiveUPP = 0L;
  525.     }
  526. }
  527.  
  528. /******************************************************************************
  529.  HasExtensionsStrip: determine if Extensions Strip is installed and running
  530.  ******************************************************************************/
  531. Boolean    HasExtensionsStrip(void)
  532. {
  533.     long    gestaltResponse;
  534.  
  535.     return(    (Gestalt(gestaltExtensionsStripAttr, &gestaltResponse) == noErr) &&
  536.             (gestaltResponse & (1L << gestaltExtensionsStripExists)) );
  537. }
  538.  
  539. #pragma mark -
  540.  
  541. /******************************************************************************
  542.  FindAProcess: run through the process list looking for the indicated program
  543.  ******************************************************************************/
  544. OSErr FindAProcess(OSType typeToFind, OSType creatorToFind,
  545.                              ProcessSerialNumberPtr processSN,
  546.                              ProcessInfoRecPtr infoRecToFill)
  547. {
  548.     OSErr    myErr    =    noErr;
  549.  
  550.     processSN->lowLongOfPSN        =    kNoProcess;
  551.     processSN->highLongOfPSN    =    0;
  552.     do
  553.     {
  554.         myErr    =    GetNextProcess(processSN);
  555.         if (myErr == noErr)
  556.             GetProcessInformation(processSN, infoRecToFill);
  557.     }
  558.     while ( (myErr == noErr) && ((infoRecToFill->processSignature != creatorToFind) ||
  559.                                  (infoRecToFill->processType != typeToFind)) );
  560.     return(myErr);
  561. }
  562.  
  563. /******************************************************************************
  564.  QuitProcess: Send a quit event to the specified process.  If you are using the
  565.                program Extensions Strip the event will be sent safely from within
  566.                its Apple Event aware context.
  567.  ******************************************************************************/
  568. void QuitProcess (ProcessSerialNumber PSN, Boolean hasExtensionsStrip)
  569. {    AEAddressDesc    applicationAddress;
  570.     AppleEvent        theEvent, returnEvent;
  571.     OSErr            err;
  572.  
  573.     AECreateDesc(typeProcessSerialNumber, &PSN, sizeof(ProcessSerialNumber), &applicationAddress);
  574.     AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &applicationAddress,
  575.                         kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  576.     AEDisposeDesc(&applicationAddress);
  577.     if (hasExtensionsStrip) {
  578.         err = SBSimpleAESend(&theEvent);
  579.     } else {
  580.         err = AESend(&theEvent, &returnEvent,
  581.                     kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  582.                     kAENormalPriority,
  583.                     kAEDefaultTimeout, nil, nil);
  584.         AEDisposeDesc(&returnEvent);
  585.     }
  586.     if (err) {
  587.         // error handling goes here
  588.         SysBeep(3);
  589.     }
  590.     AEDisposeDesc(&theEvent);
  591. }
  592.  
  593. /******************************************************************************
  594.  MouseInMyBounds: mouse is over my total clickable area
  595.  ******************************************************************************/
  596.  static Boolean MouseInMyBounds(MyGlobalHandle globH, WindowRef win,
  597.                                                      DragReference theDrag)
  598.  {
  599.     Boolean        result = false;
  600.     Point        theMouse;
  601.     Rect        hotBounds;
  602.     
  603.     if (GetDragMouse(theDrag, &theMouse, 0L) == noErr) {
  604.         GlobalToLocal(&theMouse);
  605.         if ((**globH).hasExtensionsStrip)
  606.             SBGetTotalModuleBounds(&hotBounds, win, (**globH).myReferenceNum);
  607.         else
  608.             hotBounds = (**globH).myBox;
  609.         
  610.         result = PtInRect(theMouse, &hotBounds);
  611.     }
  612.     
  613.     return(result);
  614.  }
  615.  
  616. void DrawMyIcon(MyGlobalHandle globH, Boolean selected)
  617. {
  618.     Rect        viewRect;
  619.     
  620.     if ((**globH).iconSuite) {
  621.     //
  622.     // Draw our icon
  623.     //
  624.         if ((**globH).hasExtensionsStrip)
  625.             SBGetModuleBounds(&viewRect, (**globH).myReferenceNum);
  626.         else
  627.             viewRect = (**globH).myBox;
  628.         
  629.         viewRect.right = viewRect.left + kIconWidth;
  630.         PlotIconSuite(&viewRect, atNone, selected ? ttSelected : ttNone, (**globH).iconSuite);
  631.     }
  632. }
  633. /******************************************************************************
  634.  MyTrackingHandler
  635.  ******************************************************************************/
  636. pascal OSErr MyTrackingHandler(short message, WindowRef win, void *handlerRefCon,
  637.                                                         DragReference theDrag)
  638. {
  639.     MyGlobalHandle    globH = (MyGlobalHandle) handlerRefCon;
  640.     ItemReference    theItem;
  641.     FlavorType        theType;
  642.     unsigned short    count, index, numFlavors, i;
  643.     
  644.     switch (message)
  645.     {
  646.         case dragTrackingEnterHandler:
  647.             // do special global initialization here
  648.             break;
  649.         
  650.         case dragTrackingEnterWindow:
  651.             // determine if we can support at least one of the drag items
  652.             (**globH).canAcceptDrag = false;        // default to rejection
  653.             if (CountDragItems(theDrag, &count) == noErr)
  654.             {
  655.                 for (index = 1; index <= count; index++)    // check all the items
  656.                 {
  657.                     if ((GetDragItemReferenceNumber(theDrag, index, &theItem) == noErr) &&
  658.                      (CountDragItemFlavors(theDrag, theItem, &numFlavors) == noErr)) {
  659.                         
  660.                         for (i = 1; i <= numFlavors; i++)    //    check all the flavors
  661.                         {
  662.                             if ((GetFlavorType(theDrag, theItem, i, &theType) == noErr) &&
  663.                                 (((**globH).acceptFiles ? (theType == flavorTypeHFS) : 0) ||
  664.                                 ((**globH).acceptText ? (theType == 'TEXT') : 0)))
  665.                             {
  666.                                 (**globH).canAcceptDrag = true;    // I like this flavor
  667.                             }
  668.                         }
  669.                     }
  670.                 }
  671.             }
  672.             break;
  673.         
  674.         case dragTrackingInWindow:
  675.             // check if the mouse is over me
  676.             if ((**globH).canAcceptDrag)
  677.                 if ((**globH).hasEntered != MouseInMyBounds(globH, win, theDrag))
  678.                 {
  679.                     (**globH).hasEntered = !(**globH).hasEntered;
  680.                     DrawMyIcon(globH, (**globH).hasEntered);
  681.                 }
  682.             break;
  683.         
  684.         case dragTrackingLeaveWindow:
  685.             // if dragTrackingInWindow didn't handle the mouse leaving our area, do it here.
  686.             if ((**globH).hasEntered)
  687.             {
  688.                 (**globH).hasEntered = false;
  689.                 DrawMyIcon(globH, false);
  690.             }
  691.             break;
  692.         
  693.         case dragTrackingLeaveHandler:
  694.             break;
  695.     }
  696.     
  697.     return((**globH).canAcceptDrag ? 0 : -1);
  698. }
  699.  
  700. /******************************************************************************
  701.  MyReceiveDropHandler
  702.  ******************************************************************************/
  703. pascal OSErr MyReceiveDropHandler(WindowRef win, void *handlerRefCon,
  704.                                                 DragReference theDrag)
  705. {
  706.     MyGlobalHandle    globH    = (MyGlobalHandle) handlerRefCon;
  707.     OSErr            result    = -1;    // default to cancel (do zoom-back animation)
  708.     
  709.     if ((**globH).hasEntered) {
  710.         
  711.         //
  712.         // process the drag here:
  713.         //
  714.         SysBeep(3);
  715.         
  716.         //
  717.         
  718.         result = 0;        // accept the drag (no zoom-back animation)
  719.     }
  720.     
  721.     return(result);
  722. }
  723.